#include <stdlib.h>
#include <stdio.h>
#include "tokenize.h"
#include "userinput.h"
#include <time.h>

unsigned long long hard_vector[64];
unsigned long long vector_size;

int collisions;
unsigned long long * possibilities;
int p_size;

FILE *vptr;
FILE *cptr;

inline unsigned long long * getArray(int numULL)
{
	return (unsigned long long *)malloc(sizeof(unsigned long long) * numULL);
}

//adds a possibility for the current token to the array of possibilities
//if adding would overflow the array then double the size of the array
//copy over, free the old array and set the old arrays pointer to the new
//array
void addPossibility(unsigned long long poss)
{
	if(collisions + 1 > p_size)
	{
		unsigned long long * ptr = getArray(p_size * 2);
		int i;
		for(i=0; i < p_size; i++)
		{
			ptr[i] = possibilities[i];
		}
		free(possibilities);
		possibilities = ptr;
		p_size *= 2;
	}
	
	possibilities[collisions] = poss;
	collisions++;
}

void printLong(unsigned long long num)
{
	int i;
	int mask = 0xFF;
	for(i=vector_size - 8; i >=0; i-=8)
	{
		printf("%c", (char)((num >> i) & mask));
	}
}

void printPossibility()
{
	int j;

	if(collisions > 1)
	{
		printf("[ ");
		for(j=0; j < collisions; j ++)
		{
			unsigned long long poss = possibilities[j];
			printLong(poss);
			if(j == collisions -1)
			{
				printf(" ");
			}
			else
			{
				printf(", ");
			}
		}
		printf("]");
	}
	else if (collisions == 1)
	{
		printLong(possibilities[0]);
	}
}

int main()
{
	unsigned long long vec_value;
	unsigned long long token;
	unsigned long long i,j;
	cptr = (FILE *)getCipherFileFromUser();
	vptr = (FILE *)getVectorFileFromUser();
	
	clock_t start = clock();
	
	//initialize the hard_vector
	for(i = 0; i < 64, (vec_value = getNextToken(vptr)) != 0; i++)
	{
		hard_vector[i] = vec_value;
		vector_size++;
	}
	
	fclose(vptr);
	//initialize possibilities array
	possibilities = getArray(10);
	p_size = 10;
	collisions = 0;
	
	//loop over all tokens in cipher text
	while((token = getNextToken(cptr)) != 0)
	{
		unsigned long long loops = (unsigned long long)1 << vector_size;
		//here we are actually checking all possibilities
		//each i corresponds to one bit mask for the hard vector
		for(i = 0; i < loops; i++)
		{
			unsigned long long sum = 0;			

			//loop over the bits of i checking if they are set or not
			//if they are add the corresponding element from the hard
			//vector to the sum
			for(j = 0; j < vector_size; j++)
			{
				if((1 << j) & i)
				{
					sum += hard_vector[vector_size - j - 1];
				}
			}
			
			//we now have the sum for the elements in the hard vector
			//corresponding to this i
			if(token == sum)
			{
				addPossibility(i);
			}

		}
		
		//we now have all the possible bit masks (as unsigned long longs) that
		//the sum of the elements in the hard vector that each of the bits
		//corresponds to equals the current token of the cipher text.
		//we could try and decide which one to print.  However, we wont.
		//we will print out the possibilities
		
		printPossibility();
		
		collisions = 0;
	}
	fclose(cptr);
	printf("\nTime elapsed: %f\n", ((double)clock() - start) / CLOCKS_PER_SEC);
	
	return 0;
}